package v4.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import v4.text.Config;
import v4.text.TextJm;

public class FileJm {
	
	private File from;
	private File to;
	private FileJmConfig config;
	
	public FileJm(File from, File to, FileJmConfig config) {
		this.from = from;
		this.to = to;
		this.config = config;
	}
	
	
	private String fromHash, toHash;
	
	public boolean jm(byte[] key) {
		if(from!=null && to!=null && from.exists() && !to.exists()) {
			byte[] buf = new byte[8192];
			FileInputStream fis = null;
			BufferedInputStream bis = null;
			FileOutputStream fos = null;
			BufferedOutputStream bos = null;
			MessageDigest digestFrom = null;
			MessageDigest digestTo = null;
			byte[] digestBuf = new byte[buf.length];
			try {
				digestFrom = MessageDigest.getInstance(config.getHash());
				digestTo = MessageDigest.getInstance(config.getHash());
			} catch (NoSuchAlgorithmException e) {
				throw new RuntimeException(e.getMessage());
			}
			try {
				fis = new FileInputStream(from);
				bis = new BufferedInputStream(fis);
				fos = new FileOutputStream(to);
				bos = new BufferedOutputStream(fos);
				int len = -1;
				int pos = 0;
				while((len=bis.read(buf))!=-1) {
					//HASH:
					System.arraycopy(buf, 0, digestBuf, 0, buf.length);
					digestFrom.update(digestBuf, 0, len);
					//JM:
					XorKit.xor(buf, len, key, pos);
					//HASH:
					System.arraycopy(buf, 0, digestBuf, 0, buf.length);
					digestTo.update(digestBuf, 0, len);
					
					bos.write(buf, 0, len);
					pos += len;
				}
				bos.flush();
				
				BigInteger fromInt = new BigInteger(1, digestFrom.digest());
				BigInteger toInt = new BigInteger(1, digestTo.digest());
				this.fromHash = fromInt.toString(16);
				this.toHash = toInt.toString(16);
				
				return true;
			} catch (FileNotFoundException e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage());
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException(e.getMessage());
			} finally {
				try {
					if(bos!=null) bos.close();
					if(fos!=null) fos.close();
					if(bis!=null) bis.close();
					if(fis!=null) fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
		return false;
	}
	
	public String encrypt(String k) {
		String text = config.rR(new java.util.Random().nextInt(16) + 16);
		return encrypt(text, k);
	}
	
	public String encrypt(String text, String k) {
		TextJm tj = new TextJm(config);
		String etext = tj.encryptAndCheck(text, k);
		if(etext != null) {
			String keystr = config.toHardpassword(text);
			byte[] key = keystr.getBytes(Charset.forName(Config.UTF8));
			jm(key);
		}
		return etext;
	}
	
	public void decrypt(String etext, String k) {
		TextJm tj = new TextJm(config);
		String text = tj.decrypt(etext, k);
		String keystr = config.toHardpassword(text);
		byte[] key = keystr.getBytes(Charset.forName(Config.UTF8));
		jm(key);
	}

	public String getFromHash() {
		return fromHash;
	}

	public String getToHash() {
		return toHash;
	}

}
